class BaseState(object):
    """Base state object. Does pretty nothing."""

    def __call__(self, client, **kwargs):
        # personally I like to minimize magic method usage
        # in objects that implement actual functionality.
        return self.act(client, **kwargs)

class DataExpectState(BaseState):
    """State that expects certan amount of data collected in client.

    (Before actual method is called.)
    """

    dataSize = None

    def getDataSize(self, client):
        return self.dataSize

    def __call__(self, client, **kwargs):
        if client.getInputBufferSize() < self.getDataSize(client):
            # delay execution untill better times
            _rv = self
        else:
            _rv = super(DataExpectState, self).__call__(client, **kwargs)
        return _rv

class StructExpectState(DataExpectState):
    """State that expects enough data for certan structure."""

    struct = None

    def getDataSize(self, client):
        # can't bind structure size since it, theoretically,
        # can dynamically change
        return client.types.calcsize(self.struct)

class DynamicDataState(BaseState):
    """State that expectd dynamic amount of data to be received.

    According to current RFB protocol, when receiving dynamic
    amount of data, data itself is always if preceded by it's size.
    (Skipping given fields first)

    Only `countFieldType` and `skipFields` must be specefied.
    """

    skipFields = None
    countFieldType = None

    dataCount = None

    def getDataSize(self, client):
        """Overload this metod if given data amount is not in bytes."""
        return self.dataCount

    def __call__(self, client, **kwargs):
        if self.skipFields:
            # not all fields have yet been skipped
            _size = client.types.calcsize(self.skipFields)
            if client.getInputBufferSize() >= _size:
                # remove padding bytes from inpud buffer
                _data = client.recvData(_size)
                self.skipFields = None
            _rv = self
        elif self.dataCount is None:
            # data count not yet received
            _struct = (self.countFieldType, )
            _size = client.types.calcsize(_struct)
            if client.getInputBufferSize() >= _size:
                _data = client.recvData(_size)
                (self.dataCount, ) = client.types.unpack(_struct, _data)
            _rv = self
        elif client.getInputBufferSize() < self.getDataSize(client):
            # not all data is yet received
            _rv = self
        else:
            assert client.getInputBufferSize() >= self.getDataSize(client)
            _rv = super(DynamicDataState, self).__call__(client, **kwargs)
        return _rv

class ReceiveStringState(DynamicDataState):
    """State for receiving string from server."""

    countFieldType = "U32"

class EncapsulatedState(BaseState):
    """Encapsulates many states.

    Each state MUST return non-callable object
    after it has served its purpose.

    """

    _hiddenStates = None
    _lastState = None

    def __init__(self, states, lastState):
        self._hiddenStates = tuple(states)
        self._lastState = lastState

    def __call__(self, client, **kwargs):
        if self._hiddenStates:
            _state = self._hiddenStates[0]
            _tail = self._hiddenStates[1:]
            _newState = _state(client, **kwargs)
            if callable(_newState):
                _tail = (_newState, ) + _tail
            self._hiddenStates = _tail
            _rv = self
        else:
            _rv = self._lastState
        return _rv

# vim: set sts=4 sw=4 et :
